package com.ruoyi.factorydata.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.ruoyi.common.utils.CacheSupportUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.factorydata.domain.*;
import com.ruoyi.factorydata.domain.vo.CraftRouteVo;
import com.ruoyi.factorydata.domain.vo.MaterialDataVo;
import com.ruoyi.factorydata.domain.vo.ProductionBomVo;
import com.ruoyi.factorydata.mapper.*;
import com.ruoyi.factorydata.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 物料数据Service业务层处理
 *
 * @author ruoyi
 * @date 2025-07-08
 */
@Service
public class MaterialDataServiceImpl extends ServiceImpl<MaterialDataMapper, MaterialData> implements IMaterialDataService {
    @Autowired
    private MaterialDataMapper materialDataMapper;

    @Autowired
    private SupplierDataMapper supplierDataMapper;

    @Autowired
    private MaterialUnitDataMapper materialUnitDataMapper;

    @Autowired
    private MaterialCategoryMapper materialCategoryMapper;

    @Autowired
    private MaterialInventoryMapper materialInventoryMapper;

    @Autowired
    private IProcessMaterialRelationService processMaterialRelationService;

    @Autowired
    private ICraftProcessMaterialRelationService craftProcessMaterialRelationService;

    @Autowired
    private ICraftRouteService craftRouteService;

    @Autowired
    private IProductionBomService productionBomService;

    @Autowired
    private CustomerDataMapper customerDataMapper;

    /**
     * 查询物料数据
     *
     * @param id 物料数据主键
     * @return 物料数据
     */
    @Override
    public MaterialData selectMaterialDataById(Long id) {
        return materialDataMapper.selectMaterialDataById(id);
    }

    /**
     * 查询物料数据列表
     *
     * @param materialData 物料数据
     * @return 物料数据
     */
    @Override
    public List<MaterialDataVo> selectMaterialDataList(MaterialData materialData) {
        List<MaterialData> materialDataList = materialDataMapper.selectMaterialDataList(materialData);

        HashMap<Long, MaterialUnitData> unitCache = new HashMap<>();
        HashMap<Long, MaterialCategory> categoryCache = new HashMap<>();
        HashMap<Long, SupplierData> supplierCache = new HashMap<>();
        HashMap<Long, String> customCache = new HashMap<>();

        List<MaterialDataVo> materialDataVos = materialDataList.stream().map(item -> {
            SupplierData supplierData = CacheSupportUtils.getFromCacheOrDB(item.getSupplierId(), supplierCache, supplierDataMapper::selectById, supplier -> supplier, false);
            MaterialCategory materialCategory = CacheSupportUtils.getFromCacheOrDB(item.getCategoryId(), categoryCache, materialCategoryMapper::selectById, category -> category, false);
            MaterialUnitData materialUnitData = CacheSupportUtils.getFromCacheOrDB(item.getMaterialUnit(), unitCache, materialUnitDataMapper::selectById, unit -> unit, false);
            String customCode = CacheSupportUtils.getFromCacheOrDB(item.getCustomerId(), customCache, customerDataMapper::selectCustomerDataById, CustomerData::getCustomerCode, false);
            List<CraftRouteVo> craftRouteVos = null;
            List<ProductionBomVo> productionBomVos = null;
            Long stockQuantity = null;
            if (materialData.getIsShort() == null || materialData.getIsShort() == 0) {
                CraftProcessMaterialRelation craftProcessMaterialRelation = new CraftProcessMaterialRelation();
                craftProcessMaterialRelation.setMaterialId(item.getId());
                List<CraftProcessMaterialRelation> craftProcessMaterialRelations = craftProcessMaterialRelationService.selectCraftProcessMaterialRelationList(craftProcessMaterialRelation);
                productionBomVos = productionBomService.selectProductionBomListByMaterialId(item.getId());
                if (!craftProcessMaterialRelations.isEmpty()) {
                    Set<Long> craftId = craftProcessMaterialRelations.stream().map(CraftProcessMaterialRelation::getCraftId).collect(Collectors.toSet());
                    craftRouteVos = craftRouteService.selectCraftRouteListByIds(new ArrayList<>(craftId));
                }
                stockQuantity = materialInventoryMapper.countMaterialInventoryList(MaterialInventory.builder().materialId(item.getId()).build());
            } else if (materialData.getIsShort() == 2) {
                stockQuantity = materialInventoryMapper.countMaterialInventoryList(MaterialInventory.builder().materialId(item.getId()).build());
            }
            String dictLabel = DictUtils.getDictLabel("material_type", item.getMaterialType());
            String manufacturingMethod = DictUtils.getDictLabel("material_manufacturing_method", item.getManufacturingMethod());
            return MaterialDataVo.builder()
                    .id(item.getId())
                    .materialCode(item.getMaterialCode())
                    .materialName(item.getMaterialName())
                    .materialType(item.getMaterialType())
                    .materialTypeName(dictLabel != null ? dictLabel : "")
                    .categoryId(item.getCategoryId())
                    .categoryName(materialCategory != null ? materialCategory.getMaterialCategoryName() : "")
                    .manufacturingMethod(item.getManufacturingMethod())
                    .manufacturingMethodName(manufacturingMethod)
                    .materialUnit(item.getMaterialUnit())
                    .materialUnitName(materialUnitData != null ? materialUnitData.getMaterialUnitName() : "")
                    .effectiveDate(item.getEffectiveDate())
                    .expirationDate(item.getExpirationDate())
                    .materialModel(item.getMaterialModel())
                    .internationalCode(item.getInternationalCode())
                    .materialSpecification(item.getMaterialSpecification())
                    .materialBrand(item.getMaterialBrand())
                    .supplierId(item.getSupplierId())
                    .supplierName(supplierData != null ? supplierData.getSupplierName() : "")
                    .customerId(item.getCustomerId())
                    .customerCode(customCode)
                    .materialStatus(item.getMaterialStatus())
                    .materialImages(item.getMaterialImages())
                    .materialAttachments(item.getMaterialAttachments())
                    .stockQuantity(stockQuantity)
                    .craftRouteVos(craftRouteVos)
                    .productionBomVos(productionBomVos)
                    .delFlag(item.getDelFlag())
                    .version(item.getVersion())
                    .createBy(item.getCreateBy())
                    .createTime(item.getCreateTime())
                    .updateBy(item.getUpdateBy())
                    .updateTime(item.getUpdateTime())
                    .remark(item.getRemark())
                    .build();
        }).collect(Collectors.toList());
        Page<MaterialData> queryData = null;
        if (materialDataList instanceof Page) {
            queryData = (Page<MaterialData>) materialDataList;
        } else {
            queryData = new Page<>(1, 100);
            queryData.setTotal(CollectionUtils.isEmpty(materialDataList)?0:materialDataList.size());
        }
        Page<MaterialDataVo> page = new Page<>(queryData.getPageNum(), queryData.getPageSize());
        page.setTotal(queryData.getTotal());
        page.addAll(materialDataVos);
        return page;
    }

    @Override
    public List<MaterialDataVo> selectMaterialDataListExcludeId(MaterialData materialData) {
        List<MaterialData> materialDataList = lambdaQuery()
                .ne(MaterialData::getId, materialData.getId())
                .eq(MaterialData::getMaterialStatus, 1)
                .eq(StringUtils.isNotBlank(materialData.getMaterialType()),MaterialData::getMaterialType, materialData.getMaterialType())
                .like(materialData.getMaterialName() != null && !materialData.getMaterialName().isBlank(), MaterialData::getMaterialName, materialData.getMaterialName())
                .like(materialData.getMaterialCode() != null && !materialData.getMaterialCode().isBlank(), MaterialData::getMaterialCode, materialData.getMaterialCode())
                .list();
        HashMap<Long, MaterialUnitData> unitCache = new HashMap<>();
        HashMap<Long, MaterialCategory> categoryCache = new HashMap<>();
        HashMap<Long, SupplierData> supplierCache = new HashMap<>();
        HashMap<Long, String> customCache = new HashMap<>();
        List<MaterialDataVo> materialDataVos = materialDataList.stream().map(item -> {
            SupplierData supplierData = CacheSupportUtils.getFromCacheOrDB(item.getSupplierId(), supplierCache, supplierDataMapper::selectById, supplier -> supplier, false);
            MaterialCategory materialCategory = CacheSupportUtils.getFromCacheOrDB(item.getCategoryId(), categoryCache, materialCategoryMapper::selectById, category -> category, false);
            MaterialUnitData materialUnitData = CacheSupportUtils.getFromCacheOrDB(item.getMaterialUnit(), unitCache, materialUnitDataMapper::selectById, unit -> unit, false);
            String customCode = CacheSupportUtils.getFromCacheOrDB(item.getCustomerId(), customCache, customerDataMapper::selectCustomerDataById, CustomerData::getCustomerCode, false);
            Long stockQuantity = materialInventoryMapper.countMaterialInventoryList(MaterialInventory.builder().materialId(item.getId()).build());
            stockQuantity=Optional.ofNullable(stockQuantity).orElse(0L);
            String dictLabel = DictUtils.getDictLabel("material_type", item.getMaterialType());
            String manufacturingMethod = DictUtils.getDictLabel("material_manufacturing_method", item.getManufacturingMethod());
            return MaterialDataVo.builder()
                    .id(item.getId())
                    .materialCode(item.getMaterialCode())
                    .materialName(item.getMaterialName())
                    .materialType(item.getMaterialType())
                    .materialTypeName(dictLabel != null ? dictLabel : "")
                    .categoryId(item.getCategoryId())
                    .categoryName(materialCategory != null ? materialCategory.getMaterialCategoryName() : "")
                    .manufacturingMethod(item.getManufacturingMethod())
                    .manufacturingMethodName(manufacturingMethod)
                    .materialUnit(item.getMaterialUnit())
                    .materialUnitName(materialUnitData != null ? materialUnitData.getMaterialUnitName() : "")
                    .effectiveDate(item.getEffectiveDate())
                    .expirationDate(item.getExpirationDate())
                    .materialModel(item.getMaterialModel())
                    .internationalCode(item.getInternationalCode())
                    .materialSpecification(item.getMaterialSpecification())
                    .materialBrand(item.getMaterialBrand())
                    .supplierId(item.getSupplierId())
                    .supplierName(supplierData != null ? supplierData.getSupplierName() : "")
                    .customerId(item.getCustomerId())
                    .customerCode(customCode)
                    .materialStatus(item.getMaterialStatus())
                    .materialImages(item.getMaterialImages())
                    .materialAttachments(item.getMaterialAttachments())
                    .stockQuantity(stockQuantity)
                    .delFlag(item.getDelFlag())
                    .version(item.getVersion())
                    .createBy(item.getCreateBy())
                    .createTime(item.getCreateTime())
                    .updateBy(item.getUpdateBy())
                    .updateTime(item.getUpdateTime())
                    .remark(item.getRemark())
                    .build();
        }).collect(Collectors.toList());

        Page<MaterialData> queryData = (Page<MaterialData>) materialDataList;
        Page<MaterialDataVo> page = new Page<>(queryData.getPageNum(), queryData.getPageSize());
        page.setTotal(queryData.getTotal());
        page.addAll(materialDataVos);
        return page;
    }

    /**
     * 新增物料数据
     *
     * @param materialData 物料数据
     * @return 结果
     */
    @Override
    public int insertMaterialData(MaterialData materialData) {
        materialData.setCreateTime(DateUtils.getNowDate());
        return materialDataMapper.insertMaterialData(materialData);
    }

    /**
     * 修改物料数据
     *
     * @param materialData 物料数据
     * @return 结果
     */
    @Transactional
    @Override
    public int updateMaterialData(MaterialData materialData) {
        materialData.setUpdateTime(DateUtils.getNowDate());
        int i = materialDataMapper.updateMaterialData(materialData);
        if (i > 0) {
            // 同步更新工序分类中该物料的分类信息
            MaterialCategory materialCategory = materialCategoryMapper.selectById(materialData.getCategoryId());
            MaterialUnitData materialUnitData = materialUnitDataMapper.selectById(materialData.getMaterialUnit());
            String materialType = DictUtils.getDictLabel("material_type", materialData.getMaterialType());
            String manufacturingMethod = DictUtils.getDictLabel("material_manufacturing_method", materialData.getManufacturingMethod());
            UpdateWrapper<ProcessMaterialRelation> processMaterialRelationUpdateWrapper = new UpdateWrapper<>();
            processMaterialRelationUpdateWrapper.lambda()
                    .set(ProcessMaterialRelation::getMaterialName, materialData.getMaterialName())
                    .set(ProcessMaterialRelation::getMaterialCode, materialData.getMaterialCode())
                    .set(ProcessMaterialRelation::getMaterialCategoryId, materialData.getCategoryId())
                    .set(ProcessMaterialRelation::getMaterialCategoryName, materialCategory.getMaterialCategoryName())
                    .set(ProcessMaterialRelation::getMaterialTypeId, materialData.getMaterialType())
                    .set(ProcessMaterialRelation::getMaterialTypeName, materialType)
                    .set(ProcessMaterialRelation::getManufacturingMethodId, materialData.getManufacturingMethod())
                    .set(ProcessMaterialRelation::getManufacturingMethodName, manufacturingMethod)
                    .set(ProcessMaterialRelation::getMaterialUnitId, materialData.getMaterialUnit())
                    .set(ProcessMaterialRelation::getMaterialUnitName, materialUnitData.getMaterialUnitName())
                    .set(ProcessMaterialRelation::getMaterialSpecification, materialData.getMaterialSpecification())
                    .eq(ProcessMaterialRelation::getMaterialId, materialData.getId());
            processMaterialRelationService.update(processMaterialRelationUpdateWrapper);
        }
        return i;
    }

    /**
     * 批量删除物料数据
     *
     * @param ids 需要删除的物料数据主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteMaterialDataByIds(Long[] ids) {
        int i = materialDataMapper.deleteBatchIds(Arrays.stream(ids).collect(Collectors.toList()));
        if (i > 0) {
            processMaterialRelationService.remove(new QueryWrapper<ProcessMaterialRelation>().lambda()
                    .in(ProcessMaterialRelation::getMaterialId, ids));
        }
        return i;
    }

    /**
     * 删除物料数据信息
     *
     * @param id 物料数据主键
     * @return 结果
     */
    @Override
    public int deleteMaterialDataById(Long id) {
        return materialDataMapper.deleteMaterialDataById(id);
    }
}